package com.tmt.im.service.service;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.tmt.im.common.enums.ChatSessionType;
import com.tmt.im.common.enums.CustomizedMsgCode;
import com.tmt.im.common.enums.IMAuthorityEnum;
import com.tmt.im.common.pojo.*;
import com.tmt.im.common.store.StoreSqlHelper;
import com.tmt.im.common.vo.NewChatSessionVo;
import com.tmt.im.common.yunxin.IYunXinMsgSender;
import com.tmt.im.service.config.beans.CurrentServiceProperties;
import com.tmt.im.service.config.beans.YunXinProperties;
import com.tmt.im.service.controller.vo.*;
import com.tmt.im.service.helper.IgniteQueryHelper;
import com.tmt.im.service.helper.PrincipalHelper;
import com.tmt.im.service.helper.SessionNotifyHelper;
import com.tmt.im.service.helper.UpdateSessionVoHelper;
import com.tmt.im.service.interfaces.IDataSender;
import com.tmt.im.service.mapstruct.ChatSessionPoJoMapStruct;
import com.tmt.springboot.common.helper.IdSnowFlake;
import com.tmt.springboot.common.restful.ExecuteResult;
import com.tmt.springboot.common.restful.IExecuteResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.ignite.Ignite;
import org.apache.ignite.cache.query.FieldsQueryCursor;
import org.apache.ignite.cache.query.SqlFieldsQuery;
import org.apache.ignite.lang.IgniteBiPredicate;
import org.apache.ignite.transactions.Transaction;
import org.apache.ignite.transactions.TransactionConcurrency;
import org.apache.ignite.transactions.TransactionIsolation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.security.Principal;
import java.sql.Timestamp;
import java.text.MessageFormat;
import java.time.OffsetDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Description TODO
 * @Author wuyi
 * @Date 2024/8/7 10:12
 * @Version 1.0
 **/

@Slf4j
@Service
public class ChatSessionService extends BaseService {

    private final IgniteBiPredicate<UUID, ChatDataKey> dataProcessor;

    private final CurrentServiceProperties serviceProperties;

    private final YunXinProperties yunXinProperties;

    private final IDataSender iDataSender;

    private final ConcurrentHashMap<Long, UUID> dataListenerMap;

    private final FriendService friendService;

    private final IYunXinMsgSender iYunXinMsgSender;

    private final ChatSessionPoJoMapStruct sessionPoJoMapStruct;

    public ChatSessionService(Ignite ignite,
                              IgniteBiPredicate<UUID, ChatDataKey> dataProcessor,
                              IDataSender iDataSender,
                              YunXinProperties yunXinProperties,
                              CurrentServiceProperties serviceProperties,
                              @Qualifier("dataListenerMap")
                              ConcurrentHashMap<Long, UUID> dataListenerMap,
                              FriendService friendService,
                              IYunXinMsgSender iYunXinMsgSender,
                              ChatSessionPoJoMapStruct sessionPoJoMapStruct) {
        super(ignite);
        this.dataProcessor = dataProcessor;
        this.iDataSender = iDataSender;
        this.serviceProperties = serviceProperties;
        this.yunXinProperties = yunXinProperties;
        this.dataListenerMap = dataListenerMap;
        this.friendService = friendService;
        this.iYunXinMsgSender = iYunXinMsgSender;
        this.sessionPoJoMapStruct = sessionPoJoMapStruct;
    }

    public boolean isFriend(Long currentUserId, Long userId) {
        String sql = MessageFormat.format("select * from {0} where ownerId =? and friendId =?", IMFriendPoJo.CACHE_NAME);
        IMFriendPoJo friendPoJo = IgniteQueryHelper.findOneBy(sql, new Object[]{currentUserId, userId}, IMFriendPoJo.class, friendCache);
        return friendPoJo != null;
    }

    public IExecuteResult<ChatSessionDetailVo> createSession(Long creatorId, NewChatSessionVo sessionVo, JSONObject yunXinResult) {
        Long id = null;
        int maxAmount = 200;
        try {
            if (yunXinResult.containsKey("tinfo")) {
                //V9版本返回的数据。
                id = yunXinResult.getJSONObject("tinfo").getLong("tid");
                maxAmount = yunXinResult.getJSONObject("tinfo").getInteger("maxusers");
            } else {
                //V10版本返回的数据。
                JSONObject teamInfo = yunXinResult.getJSONObject("data").getJSONObject("team_info");
                teamInfo.getLong("team_id");
                maxAmount = teamInfo.getInteger("members_limit");
            }
        } catch (Exception ex) {
            return ExecuteResult.failure("云信平台返回数据结构异常", null);
        }

        String avatarUrl = yunXinProperties.getGroupAvatarUri().replace("{tid}", "" + id);

        ChatSessionPoJo pojo = ChatSessionPoJo.builder()
                .id(id)
                .type(ChatSessionType.GROUP.name())
                .maxMemberAmount(maxAmount)
                .memberAmountLimit(maxAmount)
                .name(sessionVo.getName())
                .avatar(avatarUrl)
                .chatBanned(0)
                //默认禁止相互间加好友
                .forbidAddFriend(false)
                //允许抢红包。
                .allowRedPackage(true)
                .joinMode(1)
                .beInvitedMode(0)
                //所有人都可以拉人入群。
                .inviteMode(1)
                .updateTeamInfoMode(0)
                .updateExtensionMode(0)
                .ownerId(creatorId)
                .creatorId(creatorId)
                .version(0L)
                .deleted(false)
                .deleteTime(null)
                .insert(true)
                .createTime(new Timestamp(System.currentTimeMillis()))
                .build();

        if (!sessionVo.getInvitedIds().contains(creatorId)) {
            sessionVo.getInvitedIds().add(creatorId);
        }

        Map<SessionMemberKey, ChatSessionMemberPoJo> memberPoJos = new HashMap<>();
        for (Long memberId : sessionVo.getInvitedIds()) {
            IMUserPoJo userPoJo = userCache.get(memberId);
            Timestamp timestamp = new Timestamp(System.currentTimeMillis());
            Long tmpId = IdSnowFlake.getId();
            ChatSessionMemberPoJo memberPoJo = ChatSessionMemberPoJo.builder()
                    .id(tmpId)
                    .mid(tmpId)
                    .memberId(memberId)
                    .memberNick(userPoJo.getNickname())
                    .sessionId(pojo.getId())
                    .inviteMsg(sessionVo.getInviteMsg())
                    .forbidRedPackage(!Objects.equals(creatorId, memberId))
                    .doNotDisturb(false)
                    .roleInSession(Objects.equals(creatorId, memberId) ? 1 : 3)
                    .chatBanned(false)
                    .deleted(false)
                    .deleteTime(null)
                    .checkStatus(1)  //创建群组时直接设置审核状态为通过.
                    .checkerId(creatorId)
                    .checkTime(timestamp)
                    .agreeStatus(1)
                    .agreeTime(timestamp)
                    .version(0L)
                    .insert(true)
                    .creatorId(creatorId)
                    .createTime(timestamp)
                    .build();
            memberPoJos.put(new SessionMemberKey(memberPoJo.getId(), pojo.getId()), memberPoJo);
        }

        //注册Ignite远程节点消息监听器
        //registerDataListener(pojo);

        try {
            //创建乐观串行事务。
            try (Transaction tx = ignite.transactions().txStart(TransactionConcurrency.OPTIMISTIC, TransactionIsolation.SERIALIZABLE)) {
                sessionCache.put(pojo.getKey(), pojo);
                sessionMemberCache.putAll(memberPoJos);
                //提交事务
                tx.commit();
            }

            //发送群创建通知
            SessionNotifyHelper.sendChangedNotify(creatorId, pojo.getId(), CustomizedMsgCode.CREATION_GROUP,
                    null, sessionMemberCache, iYunXinMsgSender);

            ChatSessionDetailVo itemVo = loadChatSessionDetailVo(creatorId, pojo, yunXinResult);
            return ExecuteResult.success(itemVo);
        } catch (Exception ex) {
            return ExecuteResult.failure(ex.getMessage(), null);
        }
    }

    public IExecuteResult<List<ChatSessionPoJo>> getAllInSession(Long creatorId, JSONObject yunXinResult, Map<Long, Long> needDeletedSessionMap) {
        if (!yunXinResult.containsKey("infos")) {
            return ExecuteResult.success(new ArrayList<>());
        }

        List<ChatSessionPoJo> list = new ArrayList<>();
        JSONArray array = yunXinResult.getJSONArray("infos");
        for (Object obj : array) {
            JSONObject json = JSONObject.from(obj);
            Long tid = json.getLong("tid");
            ChatSessionPoJo poJo = sessionCache.get(tid);
            if (poJo != null) {
                list.add(poJo);
            } else {
                Long ownerId = json.getLong("owner");
                //需要从云信平台中删除的群组ID。
                needDeletedSessionMap.put(tid, ownerId);
            }
        }
        return ExecuteResult.success(list);
    }

    /**
     * 根据群组ID，查询群组对象。
     *
     * @param sessionId
     * @return
     */
    public ChatSessionPoJo findById(Long sessionId) {
        return sessionCache.get(sessionId);
    }

    public IMUserPoJo getCurrentUser(Long currentUserId) {
        return userCache.get(currentUserId);
    }

    /**
     * 根据群组ID，查询群组详细信息。
     *
     * @param sessionId
     * @return
     */
    public IExecuteResult<ChatSessionDetailVo> getSessionDetail(Long sessionId, JSONObject yunXinResult, Principal principal) {
        ChatSessionPoJo pojo = sessionCache.get(sessionId);
        if (pojo == null) {
            return ExecuteResult.failure("目标群组不存在", null);
        }

        Long currentUserId = PrincipalHelper.getCurrentUserId(principal);
        ChatSessionDetailVo vo = loadChatSessionDetailVo(currentUserId, pojo, yunXinResult);
        return ExecuteResult.success(vo);
    }

    /**
     * 解散群组
     * 先判断当前用户是否有删除聊天群组的权限:要么是群主，要么有群管理权限。
     * 特别地，本接口不支持双人聊天群的删除，只能在其中一方注销账号时才能删除。
     *
     * @param currentUserId
     * @param sessionId
     * @param principal
     * @return
     */
    public IExecuteResult<Boolean> deleteSession(Long currentUserId, Long sessionId, Principal principal) {
        ChatSessionPoJo sessionPoJo = sessionCache.get(sessionId);
        if (sessionPoJo == null) {
            return ExecuteResult.failure("目标群组不存在", false);
        }

        if (ChatSessionType.DOUBLE.name().equals(sessionPoJo.getType())) {
            //判断当前用户是否在聊天群组中。
            boolean inSession = inSession(currentUserId, sessionPoJo);
            if (!inSession) {
                return ExecuteResult.failure("无权清除聊天内容", false);
            }
            //如果是双人聊天，则直接清除会话所有的聊天内容，但不删除会话对象。
            String sql = MessageFormat.format("delete from {0} where sessionId = ?", ChatDataPoJo.CACHE_NAME);
            SqlFieldsQuery query = new SqlFieldsQuery(sql).setArgs(sessionPoJo.getId());
            try (FieldsQueryCursor<List<?>> cursor = chatDataCache.query(query)) {
                cursor.getAll();
            }
            //取消群组数据监听器
            //unregisterDataListener(sessionId);
            return ExecuteResult.success("聊天内容已清除", true);
        }

        //以下为解散群聊流程。

        //是否是群主
        boolean isOwner = isSessionOwner(currentUserId, sessionPoJo);
        //是否是管理员
        boolean isManager = isManager(currentUserId, sessionId);
        //是否有群管理权限
        boolean hasAuthenticated = hasAuthenticated(principal, List.of(IMAuthorityEnum.IM_AUTH_ALL, IMAuthorityEnum.IM_AUTH_SESSION_ALL));
        if (isOwner || isManager || hasAuthenticated) {
            String sql = MessageFormat.format("select * from {0} where sessionId = ?",
                    ChatSessionMemberPoJo.CACHE_NAME);
            List<ChatSessionMemberPoJo> sessionMemberPoJos = IgniteQueryHelper.findAllBy(sql, new Object[]{sessionId},
                    ChatSessionMemberPoJo.class, sessionMemberCache);
            Map<SessionMemberKey, ChatSessionMemberPoJo> map = new LinkedHashMap<>();
            for (ChatSessionMemberPoJo sessionMemberPoJo : sessionMemberPoJos) {
                sessionMemberPoJo.setDeleted(true);
                sessionMemberPoJo.setInsert(false);
                sessionMemberPoJo.setDeleteTime(new Timestamp(System.currentTimeMillis()));
                map.put(sessionMemberPoJo.getKey(), sessionMemberPoJo);
            }
            //仅修改删除标志，由定时任务完成相关数据的删除。
            sessionPoJo.setDeleted(true);
            sessionPoJo.setInsert(false);
            try {
                try (Transaction tx = ignite.transactions().txStart(TransactionConcurrency.OPTIMISTIC, TransactionIsolation.SERIALIZABLE)) {
                    sessionCache.put(sessionPoJo.getKey(), sessionPoJo);
                    sessionMemberCache.putAll(map);
                    tx.commit();
                }

                //向群成员发送一条群解散自定义通知消息。
                SessionNotifyHelper.sendChangedNotify(currentUserId, sessionPoJo.getId(), CustomizedMsgCode.DISSOLVE,
                        null, sessionMemberCache, iYunXinMsgSender);

                return ExecuteResult.success("成功解散目标聊天群组", true);
            } catch (Exception ex) {
                return ExecuteResult.failure(ex.getMessage(), false);
            }
        }

        return ExecuteResult.failure("无权解散目标聊天群组", false);
    }

    public IExecuteResult<Boolean> bannedSession(Long currentUserId, Long sessionId, int bannedType, Principal principal) {
        ChatSessionPoJo sessionPoJo = sessionCache.get(sessionId);
        //是否是群主
        boolean isOwner = isSessionOwner(currentUserId, sessionPoJo);
        //是否是管理员
        boolean isManager = isManager(currentUserId, sessionId);
        //是否有群管理权限
        boolean hasAuthenticated = hasAuthenticated(principal, List.of(IMAuthorityEnum.IM_AUTH_ALL, IMAuthorityEnum.IM_AUTH_SESSION_ALL));
        if (isOwner || isManager || hasAuthenticated) {
            sessionPoJo.setInsert(false);
            sessionPoJo.setChatBanned(bannedType);
            sessionCache.put(sessionPoJo.getKey(), sessionPoJo);
            return ExecuteResult.success(true);
        }
        return ExecuteResult.success("权限不足", false);
    }

    public IExecuteResult<Boolean> updateSessionJoinMode(Long currentUserId, Long sessionId, int joinMode, Principal principal) {
        ChatSessionPoJo sessionPoJo = sessionCache.get(sessionId);
        //是否是群主
        boolean isOwner = isSessionOwner(currentUserId, sessionPoJo);
        //是否是管理员
        boolean isManager = isManager(currentUserId, sessionId);
        //是否有群管理权限
        boolean hasAuthenticated = hasAuthenticated(principal, List.of(IMAuthorityEnum.IM_AUTH_ALL, IMAuthorityEnum.IM_AUTH_SESSION_ALL));
        if (isOwner || isManager || hasAuthenticated) {
            sessionPoJo.setInsert(false);
            sessionPoJo.setJoinMode(joinMode);
            sessionPoJo.setInviteMode(1);
            sessionCache.put(sessionPoJo.getKey(), sessionPoJo);
            return ExecuteResult.success(true);
        }
        return ExecuteResult.success("权限不足", false);
    }

    public IExecuteResult<Boolean> transferSession(Long currentUserId, Long sessionId, Long newOwnerId, boolean leave, Principal principal) {
        ChatSessionPoJo sessionPoJo = sessionCache.get(sessionId);
        if (sessionPoJo == null) {
            return ExecuteResult.failure("目标群组不存在", false);
        }

        //是否是群主
        boolean isOwner = isSessionOwner(currentUserId, sessionPoJo);
        //是否是管理员
        boolean isManager = isManager(currentUserId, sessionId);
        //是否有群管理权限
        boolean hasAuthenticated = hasAuthenticated(principal, List.of(IMAuthorityEnum.IM_AUTH_ALL, IMAuthorityEnum.IM_AUTH_SESSION_ALL));
        if (isOwner || isManager || hasAuthenticated) {
            try (Transaction tx = ignite.transactions().txStart(TransactionConcurrency.OPTIMISTIC, TransactionIsolation.SERIALIZABLE)) {
                ChatSessionMemberPoJo memberPoJo1 = getSessionMemberBy(sessionPoJo.getOwnerId(), sessionId);
                memberPoJo1.setRoleInSession(3);
                memberPoJo1.setForbidRedPackage(true);

                ChatSessionMemberPoJo memberPoJo2 = getSessionMemberBy(newOwnerId, sessionId);
                memberPoJo2.setRoleInSession(1);
                memberPoJo2.setForbidRedPackage(false);

                sessionPoJo.setInsert(false);
                sessionPoJo.setOwnerId(newOwnerId);

                //更新缓存和数据库
                sessionCache.put(sessionPoJo.getKey(), sessionPoJo);
                sessionMemberCache.put(memberPoJo2.getKey(), memberPoJo2);
                if (leave) {
                    sessionMemberCache.remove(memberPoJo1.getKey());
                } else {
                    sessionMemberCache.put(memberPoJo1.getKey(), memberPoJo1);
                }
                tx.commit();
            }
            return ExecuteResult.success(true);
        }
        return ExecuteResult.failure("无权转让群主", false);
    }


    public IExecuteResult<Boolean> addManager(Long operatorId, Long tid, List<Long> managers, Principal principal) {
        return _updateManager(operatorId, tid, managers, principal, true);
    }

    public IExecuteResult<Boolean> removeManager(Long operatorId, Long tid, List<Long> managers, Principal principal) {
        return _updateManager(operatorId, tid, managers, principal, false);
    }

    public void removeMember(SessionMemberKey memberKey) {
        sessionMemberCache.remove(memberKey);
    }

    public void pullInBlackBill(Long currentUserId, SessionBlackBillRequest request) {
        String sql = MessageFormat.format("select * from {0} where sessionId = ? and userId = ?", BlackBillPoJo.CACHE_NAME);
        BlackBillPoJo blackBillPoJo = IgniteQueryHelper.findOneBy(sql, new Object[]{request.getTid(), request.getUserId()}, BlackBillPoJo.class, blackBillCache);
        if (!request.getPullIn()) {
            if (blackBillPoJo != null) {
                blackBillCache.remove(blackBillPoJo.getKey());
            }
        } else if (blackBillPoJo == null) {
            blackBillPoJo = BlackBillPoJo.builder()
                    .id(IdSnowFlake.getId())
                    .sessionId(request.getTid())
                    .userId(request.getUserId())
                    .creatorId(currentUserId)
                    .version(0L)
                    .createTime(new Timestamp(System.currentTimeMillis()))
                    .insert(true)
                    .build();
            blackBillCache.put(blackBillPoJo.getKey(), blackBillPoJo);
        }
    }

    public boolean inBlackBill(Long tid, Long userId) {
        String sql = MessageFormat.format("select * from {0} where sessionId = ? and userId = ?", BlackBillPoJo.CACHE_NAME);
        BlackBillPoJo blackBillPoJo = IgniteQueryHelper.findOneBy(sql, new Object[]{tid, userId}, BlackBillPoJo.class, blackBillCache);
        return blackBillPoJo != null;
    }

    public ChatSessionMemberPoJo getSessionMemberBy(Long memberId, Long tid) {
        String sql = MessageFormat.format("select * from {0} where memberId =? and sessionId =?", ChatSessionMemberPoJo.CACHE_NAME);
        return IgniteQueryHelper.findOneBy(sql, new Object[]{memberId, tid}, ChatSessionMemberPoJo.class, sessionMemberCache);
    }

    public ChatSessionMemberPoJo getSessionMemberBy(Long applyId) {
        String sql = MessageFormat.format("select * from {0} where mid =?", ChatSessionMemberPoJo.CACHE_NAME);
        return IgniteQueryHelper.findOneBy(sql, new Object[]{applyId}, ChatSessionMemberPoJo.class, sessionMemberCache);
    }

    public List<ChatSessionMemberPoJo> getSessionAllMemberBy(Long tid, int count) {
        String sql = MessageFormat.format("select * from {0} where checkStatus = ? and sessionId =? order by roleInSession asc, createTime asc limit 0, ? ", ChatSessionMemberPoJo.CACHE_NAME);
        return IgniteQueryHelper.findAllBy(sql, new Object[]{1, tid, count}, ChatSessionMemberPoJo.class, sessionMemberCache);
    }

    public List<ChatSessionMemberPoJo> slideQueryMemberInSession(Long ownerId, SlideQueryRequest request) {
        if (request.getStartId() == null || request.getStartId() == 0) {
            request.setStartId(Long.MAX_VALUE);
        }

        List<Object> params = new ArrayList<>();
        params.add(false);
        params.add(request.getTid());

        String flag1 = "";
        if (request.getMemberType() != 0) {
            if (request.getMemberType() == 1) {
                flag1 = " and roleInSession != ?";
            } else if (request.getMemberType() == 2) {
                flag1 = " and roleInSession = ?";
            }
            params.add(3);
        }


        String flag2 = "";
        if (request.getBannedType() != 0) {
            if (request.getBannedType() == 1) {
                flag2 = " and chatBanned = ?";
            } else if (request.getBannedType() == 2) {
                flag2 = " and chatBanned != ?";
            }
            params.add(true);
        }
        params.add(request.getStartId());
        params.add(0);
        params.add(request.getWindowSize());

        String flag3 = request.getBackward() ? ">" : "<";
        String flag4 = request.getBackward() ? "asc" : "desc";

        String sql = MessageFormat.format("select * from {0} where deleted = ? and sessionId = ?{1}{2} and mid {3} ? order by mid {4} limit ?, ?",
                ChatSessionMemberPoJo.CACHE_NAME, flag1, flag2, flag3, flag4);
        List<ChatSessionMemberPoJo> memberPoJos = IgniteQueryHelper.findAllBy(sql, params.toArray(), ChatSessionMemberPoJo.class, sessionMemberCache);
        if (CollectionUtils.isEmpty(memberPoJos)) {
            return memberPoJos;
        }

        if ("desc".equals(flag4)) {
            //如果是向前查询则需要倒序一下，保持升序排序。
            memberPoJos = memberPoJos.stream().sorted(Comparator.comparingLong(ChatSessionMemberPoJo::getId)).toList();
        }
        return memberPoJos;
    }

    public long pageQueryMemberInSession(long tid, int pageIndex, int pageSize, List<ChatSessionMemberPoJo> memberPoJos) {
        String sql = MessageFormat.format("select count(*) from {0} where checkStatus = 1 and sessionId = ? ", ChatSessionMemberPoJo.CACHE_NAME);
        long total = IgniteQueryHelper.getCountBy(sql, new Object[]{tid}, sessionMemberCache);

        sql = MessageFormat.format("select * from {0} where checkStatus = 1 and sessionId = ? order by roleInSession limit ?, ?", ChatSessionMemberPoJo.CACHE_NAME);
        List<ChatSessionMemberPoJo> memberPoJos2 = IgniteQueryHelper.findAllBy(sql, new Object[]{tid, pageIndex * pageSize, pageSize},
                ChatSessionMemberPoJo.class, sessionMemberCache);
        memberPoJos.addAll(memberPoJos2);
        return total;
    }

    public IExecuteResult<ChatSessionDetailVo> updateSession(UpdateSessionRequest request, Principal principal) {
        ChatSessionPoJo sessionPoJo = sessionCache.get(request.getTid());
        if (sessionPoJo == null) {
            return ExecuteResult.failure("目标群组不存在", null);
        }

        if (request.getMembersLimit() != null && request.getMembersLimit() > sessionPoJo.getMaxMemberAmount()) {
            return ExecuteResult.failure("成员数量限额不能大于云信平台允许的最大群成员数量：" + sessionPoJo.getMaxMemberAmount(), null);
        }

        //是否是群主
        Long currentUserId = PrincipalHelper.getCurrentUserId(principal);
        boolean isOwner = isSessionOwner(currentUserId, sessionPoJo);
        //是否是管理员
        boolean isManager = isManager(currentUserId, sessionPoJo.getId());
        //是否有群管理权限
        boolean hasAuthenticated = hasAuthenticated(principal, List.of(IMAuthorityEnum.IM_AUTH_ALL, IMAuthorityEnum.IM_AUTH_SESSION_ALL));
        if (isOwner || isManager || hasAuthenticated) {
            //有限制的对少数属性进行赋值。
            UpdateSessionVoHelper.copyProperties(request, sessionPoJo);
            //更新聊天会话信息。
            sessionPoJo.setInsert(false);
            sessionCache.put(sessionPoJo.getKey(), sessionPoJo);
            ChatSessionDetailVo detailVo = loadChatSessionDetailVo(currentUserId, sessionPoJo, null);
            return ExecuteResult.success(detailVo);
        }
        return ExecuteResult.failure("无权更新目标聊天群组配置信息", null);
    }

    public List<ChatSessionDetailVo> loadChatSessionDetailVos(Long currentUserId, List<ChatSessionPoJo> sessionPoJos) {
        List<ChatSessionDetailVo> voList = new ArrayList<>();
        for (ChatSessionPoJo sessionPoJo : sessionPoJos) {
            ChatSessionDetailVo vo = loadChatSessionDetailVo(currentUserId, sessionPoJo, null);
            voList.add(vo);
        }
        return voList;
    }

    public ChatSessionDetailVo loadChatSessionDetailVo(Long currentUserId, ChatSessionPoJo sessionPoJo, JSONObject yunXinResult) {
        ChatSessionDetailVo vo = sessionPoJoMapStruct.toChatSessionDetailVo(sessionPoJo);
        //群组头像。
        String avatarUrl = "http://" + serviceProperties.getExternalManagerService() + vo.getAvatar();
        vo.setAvatar(avatarUrl);
        ChatSessionMemberPoJo memberPoJo = getSessionMemberBy(currentUserId, vo.getId());
        if (memberPoJo != null) {
            vo.setRoleInSession(memberPoJo.getRoleInSession());
        }

        List<MemberInfo> list = new ArrayList<>();
        vo.setMembers(list);

        //查询群组的群主、管理员，以及普通会员, 最多返回20条。
        List<ChatSessionMemberPoJo> memberPoJos = getSessionAllMemberBy(vo.getId(), 20);
        if (CollectionUtils.isEmpty(memberPoJos)) {
            return vo;
        }

        for (ChatSessionMemberPoJo poJo : memberPoJos) {
            MemberInfo memberInfo = getMemberInfoBy(currentUserId, poJo);
            list.add(memberInfo);
        }

        if (yunXinResult != null) {
            try {
                JSONObject ownerJson = yunXinResult.getJSONObject("tinfo").getJSONObject("owner");
                List<LinkedHashMap<String, Object>> admins = yunXinResult.getJSONObject("tinfo").getObject("admins",
                        new TypeReference<>() {
                        });
                List<LinkedHashMap<String, Object>> memberList = yunXinResult.getJSONObject("tinfo").getObject("members",
                        new TypeReference<>() {
                        });

                for (MemberInfo memberInfo : list) {
                    boolean syncFlag = switch (memberInfo.getRoleInSession()) {
                        case 1 -> Objects.equals("" + memberInfo.getId(), ownerJson.get("accid"));
                        case 2 ->
                                admins.stream().anyMatch(x -> Objects.equals(x.get("accid"), "" + memberInfo.getId()));
                        default ->
                                memberList.stream().anyMatch(x -> Objects.equals(x.get("accid"), "" + memberInfo.getId()));
                    };
                    memberInfo.setSyncYunXin(syncFlag);
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        return vo;
    }

    @Deprecated
    public void unregisterDataListener(Long sessionId) {
        UUID listener = dataListenerMap.remove(sessionId);
        if (listener != null) {
            igniteMessaging.stopRemoteListen(listener);
            log.info("停止监听群组(ID={})的数据", sessionId);
        }
    }

    public List<MemberInfo> getMemberInfoBy(Long currentUserId, List<ChatSessionMemberPoJo> memberPoJos) {
        List<MemberInfo> list = new ArrayList<>();
        for (ChatSessionMemberPoJo memberPoJo : memberPoJos) {
            MemberInfo memberInfo = getMemberInfoBy(currentUserId, memberPoJo);
            list.add(memberInfo);
        }
        return list;
    }

    public MemberInfo getMemberInfoBy(Long currentUserId, ChatSessionMemberPoJo poJo) {
        MemberInfo memberInfo = new MemberInfo();
        BeanUtils.copyProperties(poJo, memberInfo);
        memberInfo.setId(poJo.getMemberId());
        memberInfo.setSyncYunXin(null);

        IMUserPoJo userPoJo = userCache.get(poJo.getMemberId());
        if (userPoJo != null) {
            memberInfo.setMemberCode(userPoJo.getMemberCode());
            memberInfo.setNickname(userPoJo.getNickname());
            memberInfo.setAvatar("http://" + serviceProperties.getExternalManagerService() + userPoJo.getAvatar());
        }

        IMUserPoJo inviter = userCache.get(poJo.getCreatorId());
        if (inviter != null) {
            memberInfo.setInviterName(inviter.getNickname());
            memberInfo.setInviterMemberCode(inviter.getMemberCode());
        }

        memberInfo.setRoleInSession(poJo.getRoleInSession());

        if (currentUserId != null) {
            //读取当前用户对成员好友的备注信息。
            IMFriendPoJo friendPoJo = friendService.getFriendBy(currentUserId, poJo.getMemberId());
            if (friendPoJo != null) {
                memberInfo.setRemark(friendPoJo.getAlias());
            }
        }
        return memberInfo;
    }

    public List<WaitingCheckMemberInfo> getWaitingCheckMemberInfoBy(List<ChatSessionMemberPoJo> memberPoJos) {
        List<WaitingCheckMemberInfo> list = new ArrayList<>();
        for (ChatSessionMemberPoJo memberPoJo : memberPoJos) {
            WaitingCheckMemberInfo memberInfo = getWaitingCheckMemberInfoBy(memberPoJo);
            list.add(memberInfo);
        }
        return list;
    }

    public WaitingCheckMemberInfo getWaitingCheckMemberInfoBy(ChatSessionMemberPoJo memberPoJo) {
        IMUserPoJo userPoJo = userCache.get(memberPoJo.getMemberId());
        ChatSessionPoJo sessionPoJo = sessionCache.get(memberPoJo.getSessionId());
        ChatSessionMemberPoJo inviterPoJo = getSessionMemberBy(memberPoJo.getCreatorId(), memberPoJo.getSessionId());
        String avatarUrl = "http://" + serviceProperties.getExternalManagerService() + userPoJo.getAvatar();
        return WaitingCheckMemberInfo.builder()
                .applyId(memberPoJo.getId())
                .nickname(userPoJo.getNickname())
                .memberCode(userPoJo.getMemberCode())
                .avatar(avatarUrl)
                .sessionName(sessionPoJo.getName())
                .checkStatus(memberPoJo.getCheckStatus())
                .inviterName(inviterPoJo.getMemberNick())
                .build();
    }

    /****************************以下为私有方法*****************************************/

    @Deprecated
    private void registerDataListener(ChatSessionPoJo pojo) {
        // Add listener for ordered messages on all remote nodes.
        igniteMessaging.remoteListen(pojo.getId(), dataProcessor);
    }

    private IExecuteResult<Boolean> _updateManager(Long operatorId, Long tid, List<Long> managers, Principal principal, boolean add) {
        ChatSessionPoJo sessionPoJo = sessionCache.get(tid);
        if (sessionPoJo == null) {
            return ExecuteResult.failure("目标群组不存在", false);
        }

        if (managers.contains(sessionPoJo.getOwnerId())) {
            return ExecuteResult.failure("管理员ID列表中不能包含群主ID", false);
        }

        //是否是群主
        boolean isOwner = isSessionOwner(operatorId, sessionPoJo);
        //是否是管理员
        boolean isManager = isManager(operatorId, tid);
        //是否有群管理权限
        boolean hasAuthenticated = hasAuthenticated(principal, List.of(IMAuthorityEnum.IM_AUTH_ALL, IMAuthorityEnum.IM_AUTH_SESSION_ALL));
        if (isOwner || isManager || hasAuthenticated) {
            try {
                Object[] objectParams = new Object[2 + managers.size()];
                objectParams[0] = 1;
                objectParams[1] = tid;
                StringBuilder params = new StringBuilder();
                for (int i = 0; i < managers.size(); i++) {
                    Long manager = managers.get(i);
                    objectParams[i + 2] = manager;
                    params.append(" or ").append("memberId = ?");
                }
                String sql = MessageFormat.format("select * from {0} where agreeStatus = ? and sessionId = ? and ({1})",
                        ChatSessionMemberPoJo.CACHE_NAME, params.substring(4));
                SqlFieldsQuery query = new SqlFieldsQuery(sql).setArgs(objectParams);
                List<ChatSessionMemberPoJo> sessionMemberPoJos = new ArrayList<>();
                try (FieldsQueryCursor<List<?>> cursor = sessionMemberCache.query(query)) {
                    StoreSqlHelper.convertTo(cursor, sessionMemberPoJos, ChatSessionMemberPoJo.class);
                    for (ChatSessionMemberPoJo memberPoJo : sessionMemberPoJos) {
                        memberPoJo.setRoleInSession(add ? 2 : 3);
                        memberPoJo.setInsert(false);
                        sessionMemberCache.put(memberPoJo.getKey(), memberPoJo);
                    }
                }
                return ExecuteResult.success(true);
            } catch (Exception ex) {
                return ExecuteResult.failure(ex.getMessage(), false);
            }
        }
        return ExecuteResult.failure("无权添加管理员", false);
    }
}

